
#include "../../include/types.h"
#include "../../include/const.h"
#include "../../include/task.h"
#include "../../include/kernelheap.h"
#include "../../include/monitor.h"
#include "../../include/keyboard.h"
#include "../../include/console.h"

cons_list_t *consoles;
extern current;

boolean init_cmd(){
  setcurrent();
  monitor_clear();
  cons_t *new_c = cmd_create_new();
  new_c->console_nr = 0; /* Pirmoji, ir niekada neištrinama */
  new_c->next = new_c;
  new_c->priew = new_c;
  consoles = (cons_list_t*) kmalloc(sizeof(cons_list_t));
  consoles->head = new_c;
  consoles->tail = new_c;
  monitor_load(0);
  return TRUE;
}

cons_t *cmd_find(u32int nr){
  
  consoles->now = consoles->head;
  if(consoles->head != consoles->tail){
    do{
      if(consoles->now->console_nr == nr){
        return consoles->now;
      }
      consoles->now = consoles->now->next;
    }while(consoles->now != consoles->head);
  }
  else{
    return consoles->head;
  }
}

cons_t *cmd_create_new(){
  cons_t *new_c = (cons_t*) kmalloc(sizeof(cons_t));
  int i;
  
  new_c->buffer = (u16int*) kmalloc(2000*sizeof(u16int));
  new_c->X = 1;
  new_c->Y = 0;
  new_c->char_color = 0x0F;
  new_c->font_color = 0x00;
  new_c->task = NULL;
  new_c->readkey = FALSE;
  new_c->attribute= (0x00 /* Juoda */ << 4) | (15  & 0x0F /* Balta */) ;
  for(i = 0; i < 80*25; i++){
    new_c->buffer[i] = 0x20 /* Tarpas */ | (new_c->attribute << 8);
  }
  new_c->buffer[0] = '$' | (0x00 /* Juoda */ << 4) | (15  & BLUE) << 8;
  
  return new_c;
}
u32int cmd_create(){
  cons_t *new_c = cmd_create_new();
  new_c->console_nr = consoles->tail->console_nr+1;
  new_c->next = consoles->head;
  new_c->priew = consoles->tail;
  
  consoles->tail->next = new_c;
  consoles->head->priew = new_c;
  consoles->tail = new_c;
  return new_c->console_nr;
}

void cmd_delete(u32int nr){
  cons_t *tmp = cmd_find(nr);
  if(consoles->head != consoles->tail){
    if(tmp->task != NULL){
      kill(tmp->task->id);
    }
    if(tmp == consoles->head){
      consoles->tail->next = consoles->head->next;
      consoles->head->next->priew = consoles->tail;
      consoles->head = consoles->head->next;
      tmp->next = NULL;
      tmp->priew = NULL;
      kfree(tmp);
      consoles->now = consoles->head;
      do{
        consoles->now->console_nr--;
        consoles->now->task->console--;
        consoles->now = consoles->now->next;
      }while(consoles->now != consoles->head);
      monitor_load(nr);
    }
    else if(tmp == consoles->tail){
      consoles->tail->priew->next = consoles->head;
      consoles->head->priew = consoles->tail->priew;
      consoles->tail = tmp->priew;
      tmp->next = NULL;
      tmp->priew = NULL;
      kfree(tmp);
      monitor_load(consoles->head->console_nr);
    }
    else{
      tmp->priew->next = tmp->next;
      tmp->next->priew = tmp->priew;
      consoles->now = tmp->next;
      while(consoles->now != consoles->head){
        consoles->now->console_nr--;
        consoles->now->task->console--;
        consoles->now = consoles->now->next;
      }
      tmp->next = NULL;
      tmp->priew = NULL;
      kfree(tmp);
      monitor_load(nr);
    }
  }
}

void clear(u32int console){
  int i = 0;
  cons_t *tmp = cmd_find(console);
  
  /* Nusistatome tarpo simbolį su įprastomis spalvomis */
  u16int blank = 0x20 /* Tarpas */ | (tmp->attribute << 8); 
  
  /* Užpildome buferį tarpais */
  for(i = 0; i < 80*25; i++){
    tmp->buffer[i] = blank;
  }
  tmp->X = 0;  /* Grąžiname kursorių atgal į pradžią */
  tmp->Y = 0;  /* Grąžiname kursorių atgal į pradžią */
}

void scroll_cmd(u32int console){
  cons_t *tmp = cmd_find(console);
  int i = 0;
  /* Nusistatome tarpo simbolį su įprastomis spalvomis */
  u16int blank = 0x20 /* Tarpas */ | (tmp->attribute << 8);  
  
  /* 25 eilė yra paskutinė, vadinasi reikia pasislinkti į viršų */
  if(tmp->Y >= 25){
    /* Perkeliame eilutes vaizdo buferyje taip kad aukščiausia būtų perrašyta */
    for(i = 0*80; i < 24*80; i++){
      tmp->buffer[i] = tmp->buffer[i+80];
    }
    /* Paskutinė eilutė dabar tuščia. Užpildome ją tarpais */
    for(i = 24*80; i < 25*80; i++){
      tmp->buffer[i] = blank;
    }
    /* Pastatome kursorių į paskutinę eilutę */
    tmp->Y = 24;
  }
}

void put(char c, u32int console){
  cons_t *tmp = cmd_find(console);

  if(current == tmp->console_nr){
    monitor_put(c);
  }
  else{
    // /* Jei simbolis yra tab'as, tai padidiname kursoriaus X, bet per tiek kad dalitusi iš 8 */
    if(c == 0x09){
      tmp->X = (tmp->X+8) & ~(8-1);
    }
    /* Jei simbolis yra carriage return */
    else if(c == '\r'){
      tmp->X = 1;
    }
    /* Jei simbolis yra nauja eilutė, gryžtame kursorium atgal ir pereiname į nauja eilutę */
    else if(c == '\n'){
      tmp->X = 0;
      tmp->Y++;
    }
    /* Visi likusieji simboliai */
    else if(c >= ' '){
      tmp->buffer[tmp->Y*80 + tmp->X] = c | (tmp->attribute << 8);
      tmp->X++;
    }
    /* Patikriname ar nereikia pereiti į nauja eilutę */
    if(tmp->X >= 80){
      tmp->X = 0;
      tmp->Y++;
    }
    scroll_cmd(console);  /* Jei reikia sukuriame nauja eilutę */
  }
}

void print(char *c, u32int console){
  int i = 0;
  
  while(c[i]){
    put(c[i++], console);
  }
}
void print_dec(u32int n, u32int console){
  s32int acc = n;
  char c[32], c2[32];
  int i = 0, j = 0;
  
  if (n == 0){
    put('0', console);
    return;
  }
  while (acc > 0){
    c[i] = '0' + acc%10;
    acc /= 10;
    i++;
  }
  c[i] = 0;
  c2[i--] = 0;
  while(i >= 0){
    c2[i--] = c[j++];
  }
  print(c2, console);
}
void print_hex(u32int n, u32int console){
  s32int tmp; 
  char noZeroes = 1;
  int i = 0;
  
  print("0x", console); /* Atspauzdiname pradžią šešioliktainio skaičiaus */
  for(i = 28; i > 0; i -= 4){
    tmp = (n >> i) & 0xF;
    if(tmp == 0 && noZeroes != 0){
      continue;
    }
    if(tmp >= 0xA){
      noZeroes = 0;
      put(tmp-0xA+'a', console);
    }
    else{
      noZeroes = 0;
      put(tmp+'0', console);
    }
  }
  tmp = n & 0xF;
  if(tmp >= 0xA){
    put(tmp-0xA+'a', console);
  }
  else{
    put(tmp+'0', console);
  }
}
